

#include "WiFi.h"
#include <Wire.h>
#include <Button2.h>
#include "esp_adc_cal.h"


#include <ESPmDNS.h> 
#include <ArduinoOTA.h>
#include "time.h"

#include <WiFiClient.h>
#include <WebServer.h> 

IPAddress ip;

WebServer server(80);

const char* host = "esp32ttgo";

const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = 8 * 3600;
const int   daylightOffset_sec = 0;

#ifndef TFT_DISPOFF
#define TFT_DISPOFF 0x28
#endif

#ifndef TFT_SLPIN
#define TFT_SLPIN   0x10
#endif

#define TFT_MOSI            19
#define TFT_SCLK            18
#define TFT_CS              5
#define TFT_DC              16
#define TFT_RST             23

#define TFT_BL          4   // Display backlight control pin
#define ADC_EN          14  //ADC_EN is the ADC detection enable port
#define ADC_PIN         34
#define BUTTON_1        35
#define BUTTON_2        0

 
Button2 btn1(BUTTON_1);
Button2 btn2(BUTTON_2);

char buff[512];
int vref = 1100;
int btnCick = false;

const char* serverIndex = "<form method='POST' action='/update' enctype='multipart/form-data'><input type='file' name='update'><input type='submit' value='Update'></form>";


/*
 An example digital clock using a TFT LCD screen to show the time.
 Demonstrates use of the font printing routines. (Time updates but date does not.)
 
 For a more accurate clock, it would be better to use the RTClib library.
 But this is just a demo. 
 
 This examples uses the hardware SPI only. Non-hardware SPI
 is just too slow (~8 times slower!)
 
 Based on clock sketch by Gilchrist 6/2/2014 1.0
 Updated by Bodmer
A few colour codes:
 
code	color
0x0000	Black
0xFFFF	White
0xBDF7	Light Gray
0x7BEF	Dark Gray
0xF800	Red
0xFFE0	Yellow
0xFBE0	Orange
0x79E0	Brown
0x7E0	Green
0x7FF	Cyan
0x1F	Blue
0xF81F	Pink

 */

#include <TFT_eSPI.h> // Graphics and font library for ST7735 driver chip
#include <SPI.h>

TFT_eSPI tft = TFT_eSPI();  // Invoke library, pins defined in User_Setup.h

uint32_t targetTime = 0;       // for next 1 second timeout

byte ohh = 99;
byte omm = 99;
boolean initial = 1;
byte xcolon = 0;
unsigned int colour = 0;

bool isClean = false;

static uint8_t conv2d(const char* p) {
  uint8_t v = 0;
  if ('0' <= *p && *p <= '9')
    v = *p - '0';
  return 10 * v + *++p - '0';
}

uint8_t hh=conv2d(__TIME__), mm=conv2d(__TIME__+3), ss=conv2d(__TIME__+6);  // Get H, M, S from compile time

void _info( char* str){
  Serial.println(str);
}

void setHostname(){
//  Serial.printf("current hostname: %s\n", WiFi.hostname().c_str()); 
  Serial.printf("update hostname to: ");
//  WiFi.hostname(hostname); 
//  Serial.printf("updated hostname: %s\n", WiFi.hostname().c_str()); 



  if (MDNS.begin(host)) {
    MDNS.addService("http", "tcp", 80);
    Serial.println("MDNS responder started");
    Serial.print("You can now connect to http://");
    Serial.println(host);
    // tft.drawString("[ DNS ] esp32ttgo  READY", tft.width() / 2, tft.height() / 2  );
  }
  
}

void WifiOFF(){
  WiFi.mode(WIFI_OFF);
}

void WifiON(){
  WiFi.mode(WIFI_STA);
  doAutoConfig(); 
}

void getNetworkTime(){
  //init and get the time
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  // printLocalTime();  
}

void setup(void) {

  Serial.begin(115200);
  Serial.println("Start");
      
  tft.init();
  tft.setRotation(1);
  tft.fillScreen(TFT_BLACK);

//  tft.setTextSize(1);

  tft.setTextColor(TFT_YELLOW, TFT_BLACK); // Note: the new fonts do not draw the background colour

  targetTime = millis() + 1000;  

  doAutoConfig();
  startServer(); 

  getNetworkTime();

    // Hostname defaults to esp8266-[ChipID]
  ArduinoOTA.setHostname(host);

  ArduinoOTA.begin();
}

void loop() {
  
  ArduinoOTA.handle();
  
  server.handleClient(); 
    
  if (targetTime < millis()) {

    if(!isClean){
      tft.fillScreen(TFT_BLACK);
      isClean=true;
    }
  
    targetTime = millis()+1000;
    ss++;              // Advance second
    if (ss==60) {
      ss=0;
      omm = mm;
      mm++;            // Advance minute
      if(mm>59) {
        mm=0;
        hh++;          // Advance hour
        if (hh>23) {
          hh=0;
        }
      }
    }

    if (ss==0 || initial) {
      initial = 0; 
    }

    // Update digital time
    byte xpos = 6;
    byte ypos = 0;
    if ( omm != mm) { // Only redraw every minute to minimise flicker
 
      tft.setTextColor(0xFBE0, TFT_BLACK); // Orange
      omm = mm; 
    }

      char buff[20];
      sprintf(buff, "%02d:%02d:%02d", hh, mm, ss );
      tft.drawCentreString(String(buff), tft.width() / 2, ypos, 7); // Overwrite the text to clear it
      
    xcolon = 65; 

    printLocalTime();
    showVoltage();
  }
}

bool isIPShown = false;

void printLocalTime()
{
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return;
  }

  if(isIPShown) return;
  isIPShown = true;

  hh = timeinfo.tm_hour;
  mm = timeinfo.tm_min;
  ss = timeinfo.tm_sec;
  
  Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");

  Serial.print("Current time: ");
  Serial.println(asctime(&timeinfo));
            
  tft.drawCentreString(asctime(&timeinfo), tft.width() / 2, tft.height() / 2 , 2 ); 

  printIP();
}

void printIP(){
  char buff[30];
  
  sprintf(buff,"%s : %d.%d.%d.%d", WiFi.SSID().c_str(), ip[0],ip[1],ip[2],ip[3]); 
  tft.drawCentreString(buff, tft.width() / 2, tft.height() / 2 + 18, 2 ); 
}

void _info( const char* str ){ 
  Serial.println(str);
  delay(500);
}

void doAutoConfig(){

  Serial.println("doAutoConfig...");
  
    //Init WiFi as Station, start SmartConfig
  WiFi.mode(WIFI_STA); // WIFI_AP_STA);

  if (!autoConfig())
  {
    Serial.println("Start smartConfig module");
    smartConfig();
  }  

  startServer();

} // END void doAutoConfig()

  

//! Long time delay, it is recommended to use shallow sleep, which can effectively reduce the current consumption
void espDelay(int ms)
{
    esp_sleep_enable_timer_wakeup(ms * 1000);
    esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
    esp_light_sleep_start();
}

void startServer(){
  
  Serial.println("startServer...");
  
  server.on("/", [](){
    Serial.println("GET /");
    server.send(200, "text/html", "<h1>ESP 32</h1>");
  });

  server.on("/clock/color/{}", []() {
    Serial.println("GET /clock/color/{}");
    String p = server.pathArg(0);
    server.send(200, "text/plain", "clock color: " + p );
  });
  
  server.on("/clock/size/{}", []() {
    Serial.println("GET /clock/size/{}");
    String p = server.pathArg(0);
    server.send(200, "text/plain", "clock size: " + p );
  });  

  server.onNotFound([]() {
    server.send(404, "text/plain", "404 Not Found!");
  });
  
  server.begin();
  Serial.println("HTTP server started");  
}

float maxV = 0;
void showVoltage()
{
    static uint64_t timeStamp = 0;
    if (millis() - timeStamp > 1000) {
        timeStamp = millis();
        uint16_t v = analogRead(ADC_PIN);
        float battery_voltage = ((float)v / 4095.0) * 2.0 * 3.3 * (vref / 1000.0);
        if(battery_voltage > maxV){
          maxV = battery_voltage;
        }
        String voltage = "Voltage : " + String(maxV) + " -> " + String(battery_voltage) + "V";
        Serial.println(voltage);
        //tft.fillScreen(TFT_BLACK);
        //tft.setTextDatum(MC_DATUM);
        tft.drawCentreString(voltage,  tft.width() / 2, tft.height() / 2 + 36, 2  );
        
    }
}


bool autoConfig()
{
  WiFi.begin();
  for (int i = 0; i < 20; i++)
  {
    int wstatus = WiFi.status();
    if (wstatus == WL_CONNECTED)
    {
      Serial.println("AutoConfig Success");
      Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str());
      Serial.printf("PSW:%s\r\n", WiFi.psk().c_str());     
      WiFi.printDiag(Serial);
      
      Serial.print("IP Address: ");
      ip = WiFi.localIP();
      Serial.println(WiFi.localIP());
      
      return true;
      //break;
    }
    else
    {
      Serial.print("AutoConfig Waiting......");
      Serial.println(wstatus); 
      
      delay(1000);
    }
  }
  Serial.println("AutoConfig Faild!" );
  return false;
  //WiFi.printDiag(Serial);
}

void smartConfig()
{

  WiFi.mode(WIFI_STA);
  Serial.println("\r\nWait for Smartconfig");
  
  WiFi.setAutoConnect(true);  // 设置自动连接
  WiFi.beginSmartConfig();
  while (1)
  {
    Serial.print("."); 
      
    if (WiFi.smartConfigDone())
    {
      Serial.println("SmartConfig Success");
      Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str());
      Serial.printf("PSW:%s\r\n", WiFi.psk().c_str());
      WiFi.setAutoConnect(true);  // 设置自动连接
      
      Serial.print("IP Address: ");
      ip = WiFi.localIP();
      Serial.println(WiFi.localIP());
  
      break;
    }
    delay(500); // 这个地方一定要加延时，否则极易崩溃重启
  }

   
}